#include<jni.h>
#include "audio-opensl.h"
#include "log-print.h"

extern "C" {
#include<libswresample/swresample.h>
#include<libavcodec/bsf.h>
#include<libavutil/frame.h>

AVFormatContext *avFormatContext;
AVCodecContext *mAvContext;
const AVCodec *mAVCodec;
AVPacket *packet;
AVFrame *frame;
SwrContext *swrContext;

AudioInfo *audioInfo;

uint8_t *out_buffer;
int out_channel_nb;
int mAudioStreamIdx = -1;

//过滤器宏开关
#define ABS_FILTER_ENABLE  1

#if ABS_FILTER_ENABLE
const AVBitStreamFilter *absFilter = nullptr;
AVBSFContext *absCtx = nullptr;
AVCodecParameters *codecpar = nullptr;
#endif

//opensl es调用 int * rate,int *channel
int createFFmpeg(JNIEnv *env, int *rate, int *channel, jstring filename) {

    const char *inputPath = env->GetStringUTFChars(filename, JNI_FALSE);
    avFormatContext = avformat_alloc_context();

    char buf[] = "";
    //打开音频地址并获取里面的内容(解封装)
    int error = avformat_open_input(&avFormatContext, inputPath, nullptr, nullptr);
    if (error != 0) {
        av_strerror(error, buf, 1024);
    }

    if (avformat_find_stream_info(avFormatContext, nullptr) < 0) {
        return -1;
    }

    av_dump_format(avFormatContext, 0, inputPath, 0);

    //获取音频的编码信息
    for (int i = 0; i < avFormatContext->nb_streams; ++i) {
        if (avFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            mAudioStreamIdx = i;
            break;
        }
    }

    //获取解码器上下文
    mAvContext = avcodec_alloc_context3(nullptr);
    if (mAvContext == nullptr) {
        return -1;
    }
    avcodec_parameters_to_context(mAvContext, avFormatContext->streams[mAudioStreamIdx]->codecpar);
    //获取解码器
    mAVCodec = avcodec_find_decoder(avFormatContext->streams[mAudioStreamIdx]->codecpar->codec_id);

    //初始化AudioInfo
    audioInfo = (AudioInfo *) malloc(sizeof(AudioInfo));
    audioInfo->avFormatContext = avFormatContext;
    audioInfo->avCodecContext = mAvContext;
    audioInfo->stream_index = mAudioStreamIdx;
    audioInfo->total_time = (int) avFormatContext->duration / 1000000;

#if ABS_FILTER_ENABLE
    //过滤器相关配置，这个与音频码流格式相关，也可以不用
    absFilter = av_bsf_get_by_name("mp3decomp");
    //过滤器分配内存
    av_bsf_alloc(absFilter, &absCtx);
    //添加解码器属性
    codecpar = avFormatContext->streams[mAudioStreamIdx]->codecpar;
    avcodec_parameters_copy(absCtx->par_in, codecpar);
    absCtx->time_base_in = avFormatContext->streams[mAudioStreamIdx]->time_base;
    //初始化过滤器上下文
    av_bsf_init(absCtx);
#endif

    //打开解码器
    if (avcodec_open2(mAvContext, mAVCodec, nullptr) != 0) {
        return -1;
    }

    //申请AVPacket
    packet = (AVPacket *) av_malloc(sizeof(AVPacket));
    //av_init_packet(packet);
    av_new_packet(packet, sizeof(AVPacket));

    //申请AVFrame
    frame = av_frame_alloc();//分配一个AVFrame结构体,AVFrame结构体一般用于存储原始数据，指向解码后的原始帧

    //得到SwrContext ，进行重采样 {start
    swrContext = swr_alloc();
    //缓存区
    out_buffer = (uint8_t *) av_malloc(44100 * 2);
    //输出的声道布局（立体声）
    //uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO;
    //输出采样位数  16位
    enum AVSampleFormat out_format = AV_SAMPLE_FMT_S16;
    //输出的采样率必须与输入相同
    int out_sample_rate = mAvContext->sample_rate;
    //swr_alloc_set_opts将PCM源文件的采样格式转换为自己希望的采样格式
    /*int swr_alloc_set_opts2(struct SwrContext **ps,
                            const AVChannelLayout *out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
                            const AVChannelLayout *in_ch_layout, enum AVSampleFormat  in_sample_fmt, int  in_sample_rate,
                            int log_offset, void *log_ctx);*/
    /*swr_alloc_set_opts(swrContext,
                       out_ch_layout,
                       out_formart,
                       out_sample_rate,
                       mAvContext->channel_layout,
                       mAvContext->sample_fmt,
                       mAvContext->sample_rate,
                       0,
                       nullptr);*/
    swr_alloc_set_opts2(&swrContext,
                        &mAvContext->ch_layout,
                        out_format,
                        out_sample_rate,
                        &mAvContext->ch_layout,
                        mAvContext->sample_fmt,
                        mAvContext->sample_rate,
                        0,
                        nullptr
    );
    swr_init(swrContext);
    //获取通道数
    //out_channel_nb = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
    out_channel_nb = mAvContext->ch_layout.nb_channels;
    *rate = mAvContext->sample_rate;
    *channel = mAvContext->ch_layout.nb_channels;
    return 0;
}

void getPcm(void **pcm, size_t *pcm_size) {
    char buf[256];
    while (true) {
        int ret = av_read_frame(avFormatContext, packet);
        if (ret != 0) {
            av_strerror(ret, buf, sizeof(buf));
            av_packet_unref(packet);
            break;
        }

        if (ret >= 0 && packet->stream_index != mAudioStreamIdx) {
            av_packet_unref(packet);
            continue;
        }

#if ABS_FILTER_ENABLE
        if (av_bsf_send_packet(absCtx, packet) < 0) {
            av_packet_unref(packet);
            continue;
        }

        if (av_bsf_receive_packet(absCtx, packet) < 0) {
            av_packet_unref(packet);
            continue;
        }
#endif
        {
            //发送待解码包
            int result = avcodec_send_packet(mAvContext, packet);
            av_packet_unref(packet);
            ALOGD("%s","发送待解码包");
            if (result < 0) {
                continue;
            }

            //接收解码数据
            while (result >= 0) {
                ALOGD("%s","接收解码数据");
                result = avcodec_receive_frame(mAvContext, frame);
                if (result == AVERROR_EOF) {
                    break;
                } else if (result == AVERROR(EAGAIN)) {
                    break;
                } else if (result < 0) {
                    av_frame_unref(frame);
                    break;
                }
                swr_convert(swrContext,
                            &out_buffer,
                            44100 * 2,
                            (const uint8_t **) frame->data,
                            frame->nb_samples);
                //缓冲区的大小
                int size = av_samples_get_buffer_size(nullptr,
                                                      out_channel_nb,
                                                      frame->nb_samples,
                                                      AV_SAMPLE_FMT_S16,
                                                      1);
                *pcm = out_buffer;
                *pcm_size = size;
                av_frame_unref(frame);
                return;
            }
        }
    }
}

AudioInfo *getAudioInfo() {
    return audioInfo;
}

void releaseFFmpeg() {
    //av_free_packet(packet);
    av_packet_free(&packet);

    av_free(out_buffer);
    av_frame_free(&frame);
    swr_free(&swrContext);
    avcodec_close(mAvContext);
    avformat_close_input(&avFormatContext);
}

}